
/**
 * 数组去重
 */
Array.prototype.unique = function () {
    let len = this.length,
        arr = [],
        obj = {};
    for (let i = 0; i < len; i++) {
        if (!obj[this[i]]) {
            obj[this[i]] = 1;
            arr.push(this[i]);
        }
    }
    return arr;
}

/**
 * 判断空对象
 * @param {*} obj 
 * @returns boolean
 */
function isEmptyObject(obj) {
    for (let key in obj) {
        return false;
    }
    return true;
}

function isEmptyObjectES6(obj) {
    if (Object.keys(obj).length) {
        return false;
    }
    return true;
}

/**
 * type类型判断
 * @param {*} Target 
 * @returns number string boolean undefined array object null
 */
function type(Target) {
    var template = {
        '[object Array]': 'array',
        '[object Object]': 'object',
    }
    if (Target === null) {
        return 'null';
    } else if (typeof (Target) === 'object') {
        return template[Object.prototype.toString.call(Target)];
    } else {
        return typeof (Target);
    }
}
// 继承
const inherit = (function () {
    var F = function () { }; // 将F当作私有变量
    return function (Target, Origin) {
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        Target.prototype.constructor = Target;
        Target.prototype.uber = Origin.prototype;
    }
}());

// 深克隆
function deepClone(Target, Origin) {
    var Origin = Origin || {};
    for (var prop in Target) {
        if (Target.hasOwnProperty(prop)) {
            if (Target[prop] !== 'null' && typeof (Target[prop]) === 'object') {
                Origin[prop] = Object.prototype.toString.call(Target[prop]) === '[object Array]' ? [] : {};
                deepClone(Target[prop], Origin[prop]);
            } else {
                Origin[prop] = Target[prop];
            }
        }
    }
    return Origin;
}

// 节流
const throttle = (fn, wait) => {
    let immediately, // 首次立即执行
        timer,
        lastTime;
    return function () {
        const context = this,
            args = arguments; // 利用闭包保存参数数组

        if (!immediately) {
            fn.apply(context, args);
            lastTime = Date.now();
            immediately = true;
        } else {
            clearTimeout(timer);
            timer = setTimeout(function () {
                if (Date.now() - lastTime >= wait) { // 距离上次执行时间大于wait
                    fn.apply(context, args);
                    lastTime = Date.now();
                }
            }, wait);
        }
    };
};

/**
 * 防抖
 * @param {*} fn 
 * @param {*} delay 延时
 */

const debounce = (fn, ms = 0) => {
    let timeoutId;
    return function (...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => fn.apply(this, args), ms);
    };
};

/**
 * bind原理
 * @param {*} obj 
 * @returns 
 */
Function.prototype.bind_ = function (obj) {
    //第0位是this，所以得从第一位开始裁剪
    var args = Array.prototype.slice.call(arguments, 1);
    var fn = this;
    return function () {
        fn.apply(obj, args);
    }
}

/**
 * =jquery after()
 * @param {*} newElement 
 * @param {*} targentElement 
 */
function insertAfter(newElement, targentElement) {
    var parent = targentElement.parentNode;
    if (parent.lastChild == targentElement) {
        parent.appendChild(newElement);
    } else {
        parent.insertBefore(newElement, targentElement.nextSibling)
    }
}

/**
 * 随机字符串
 * @param {*} length 
 * @returns randomString(6)
 */
function randomString(length) {
    var str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var result = '';
    for (var i = length; i > 0; --i)
        result += str[Math.floor(Math.random() * str.length)];
    return result;
}

/**
 * 判断微信移动端/微信小程序端
 * @returns string
 */
function isWechatType() {
    var type = '';
    var ua = navigator.userAgent.toLocaleLowerCase();
    if (ua.indexOf('micromessenger') >= 0) {
        if (ua.indexOf('miniprogram') >= 0) {
            type = 'miniprogram';
        }
        else {
            type = 'wechat';
        }
    }
    return type;
}
/**
 * 判断是否是h5
 * @returns 
 */
function isH5() {
    var reg = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i;
    if (navigator.userAgent.match(reg)) {
        return true;
    }
    return false;
}

/**
 * 浏览器显示/隐藏监听
 * @param {*} hideFn 隐藏执行方法
 * @param {*} showFn 显示执行方法
 */
function visibilityChange(hideFn, showFn) {
    document.addEventListener('visibilitychange', function () {
        if (document.hidden) {
            // 隐藏
            hideFn();
        } else {
            // 显示
            showFn();
        }
    });
}

/**
 * 数字千位格式化
 * @param {*} num 数字
 */
function moneyFormat(num) {
    return (num + "").replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, "$1,");
}


/**
 * 获取url参数
 * @returns {}
 */
function getUrlQuery() {
    var url = location.href;
    var obj = new Object();
    var i = url.indexOf("?");
    if (i > 0) {
        url = url.substring(i + 1, url.length);
        i = url.indexOf("#");
        if (i > 0) {
            obj.page = url.substring(i + 1, url.length);
            url = url.substring(0, i);
        }
        var params = url.split("&");
        for (var x = 0; x < params.length; x++) {
            var a = params[x].indexOf("=");
            var k = params[x].substring(0, a);
            var v = unescape(params[x].substring(a + 1, params[x].length));
            obj[k] = v;
        }
    }
    return obj;
}


//查看滚动条滚动距离
function getScrollOffset() {
    return {
        x: document.documentElement.scrolLeft || document.body.scrolLeft,
        y: document.documentElement.scrolTop || document.body.scrolTop
    }
}

/**
 * json序列化显示
 * 调用 `<pre>${syntaxHighlight(json)}</pre>`
 */
function syntaxHighlight(json) {
    if (typeof json != 'string') {
        json = JSON.stringify(json, undefined, 2);
    }
    json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        var cls = 'number';
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'key';
            } else {
                cls = 'string';
            }
        } else if (/true|false/.test(match)) {
            cls = 'boolean';
        } else if (/null/.test(match)) {
            cls = 'null';
        }
        return '<span class="' + cls + '">' + match + '</span>';
    });
}


/**
 * 禁止鼠标滚动事件
 */

//阻止浏览器事件
function disabledMouseWheel() {
    document.addEventListener('DOMMouseScroll', scrollFunc, { passive: false });
    document.addEventListener('mousewheel', scrollFunc, { passive: false });
}
//取消阻止浏览器事件
function cancelDisMouseWheel() {
    document.removeEventListener('DOMMouseScroll', scrollFunc, false);
    document.removeEventListener('mousewheel', scrollFunc, false);
}
function scrollFunc(evt) {
    evt = evt || window.event;
    if (evt.preventDefault) {
        // Firefox  
        evt.preventDefault();
        evt.stopPropagation();
    } else {
        // IE  
        evt.cancelBubble = true;
        evt.returnValue = false;
    }
    return false;
}


/**
 * 剩余时间
 * @param {2020/05/03 23:59:59} dateEnd
 * 剩余8天6小时31分钟06秒
 */
function diffTime(dateEnd) {
    //结束时间
    var dateEnd = dateEnd || "2030/05/20 23:59:59";
    //开始时间
    var dateStart = new Date();
    //时间差毫秒数
    var diff = new Date(dateEnd).getTime() - dateStart.getTime();
    //计算相差天数
    var days = Math.floor(diff / (24 * 3600 * 1000));
    //计算天数后剩余毫秒数
    var diffDayRest = diff % (24 * 3600 * 1000);
    //计算相差小时数
    var hours = Math.floor(diffDayRest / (3600 * 1000));
    //计算小时数后剩余毫秒数
    var diffHourRest = diff % (3600 * 1000);
    //计算相差分钟数
    var minutes = Math.floor(diffHourRest / (60 * 1000));
    //计算分钟数后剩余毫秒数
    var diffMinuteRest = diffHourRest % (60 * 1000);
    //计算相差秒数
    var seconds = Math.round(diffMinuteRest / 1000);

    var time = `剩余${days}天${hours}小时${Math.abs(minutes) > 9 ? minutes : "0" + minutes}分钟${Math.abs(seconds) > 9 ? seconds : "0" + seconds}秒`;
    return time;
}

/**
 * 
 * @param {new Date()} time // 时间
 * @param {yyyy-mm-dd hh:ii:ss} format //返回格式，默认 yyyy-mm-dd
 * formatTime(null, 'yyyy-mm-dd hh:ii:ss') 2020-05-12 17:23:15
 */
function formatTime(time, format) {
    var time = time || new Date();
    var year = time.getFullYear();
    var month = time.getMonth() + 1 > 9 ? time.getMonth() + 1 : '0' + (time.getMonth() + 1);
    var day = time.getDate() > 9 ? time.getDate() : '0' + time.getDate();
    var hour = time.getHours() > 9 ? time.getHours() : '0' + time.getHours();
    var minute = time.getMinutes() > 9 ? time.getMinutes() : '0' + time.getMinutes();
    var second = time.getSeconds() > 9 ? time.getSeconds() : '0' + time.getSeconds;

    var date = year + '-' + month + '-' + day;
    return format == 'yyyy-mm-dd hh:ii:ss' ? date + ' ' + hour + ':' + minute + ':' + second : date
}